package com.william.jdbcplus.core.query;

import com.william.jdbcplus.core.conditions.segment.MergeSegments;
import com.william.jdbcplus.core.conditions.wrap.AbstractWrap;
import com.william.jdbcplus.core.metadata.TableColumnInfo;
import com.william.jdbcplus.core.metadata.TableHelperUtil;
import com.william.jdbcplus.core.metadata.TableInfo;
import com.william.jdbcplus.core.toolkit.StringPool;
import com.william.jdbcplus.common.entity.Entity;
import com.william.jdbcplus.core.enums.SqlKeyword;
import lombok.Getter;
import lombok.Setter;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import static java.util.stream.Collectors.joining;

/**
 * Entity 对象封装操作类
 *
 * @author niliwei
 */
@Getter
@Setter
public class EntityWrap<T extends Entity> extends AbstractWrap<String, EntityWrap<T>> {

    private EntityLambdaWrap<T> lambdaWrapper = null;

    private Class<T> entityClass;

    private final int maxInSet = 1000;

    private TableInfo table;

    private EntityWrap() {
        initNeed();
    }

    public EntityWrap(Class<T> clazz) {
        this.entityClass = clazz;
        this.table = TableHelperUtil.getTableInfo(entityClass);
        initNeed();
    }

    /**
     * 按实体对象初始化
     * 自动构建查询条件，按实体的非空属性全部相等条件连接查询
     */
    public void EntityWrap(T entity) throws Exception {
        if (entity == null) {
            throw new Exception("entity cannot be null");
        }

        this.entityClass = TableHelperUtil.getEntityClass(entity);
        this.table = TableHelperUtil.getTableInfo(entityClass);
        initNeed();

        //构造查询条件
        Map<String, Object> columnMap = new HashMap<>();
        Map<String, Object> attrMap = TableHelperUtil.getEntityAttrMapWithoutLogicDelete(entity);
        for (Map.Entry<String, Object> attr : attrMap.entrySet()) {
            if (attr.getValue() != null) {
                columnMap.put(attr.getKey(), attr.getValue());
            }
        }

        for (Map.Entry<String, Object> column : columnMap.entrySet()) {
            this.eq(column.getKey(), column.getValue());
        }
    }

    /**
     * 非对外公开的构造方法,只用于生产嵌套 sql
     *
     * @param entityClass 本不应该需要的
     */
    private EntityWrap(Class<T> entityClass, Map<String, Object> paramNameValuePairs, MergeSegments mergeSegments) {
        this.entityClass = entityClass;
        this.paramNameValuePairs = paramNameValuePairs;
        this.expression = mergeSegments;
        this.table = TableHelperUtil.getTableInfo(entityClass);
    }

    /**
     * 返回一个支持 lambda 函数写法的 wrapper
     */
    public EntityLambdaWrap<T> lambda() {
        if (lambdaWrapper == null) {
            lambdaWrapper = new EntityLambdaWrap<>(paramNameValuePairs, expression, this);
        }
        return lambdaWrapper;
    }

    /**
     * 用于生成嵌套 sql
     * <p>
     * 故 sqlSelect 不向下传递
     * </p>
     */
    @Override
    protected EntityWrap<T> instance() {
        return new EntityWrap<>(entityClass, paramNameValuePairs, new MergeSegments());
    }

    @Override
    public EntityWrap<T> selectAll(Class<?> clazz) {
        String selectAllColumn = TableHelperUtil.getSelectAllColumnNoTable(clazz);
        return doIt(SqlKeyword.SELECT, selectAllColumn);
    }

    @Override
    public String columnToString(String column) {
        // column为实体字段名
        String columnSql = TableHelperUtil.getEntityFieldColumn(this.entityClass, column);
        return columnSql;
    }

    /**
     * 多字段转换为逗号 "," 分割字符串
     *
     * @param columns 多字段
     */
    @Override
    public String columnsToString(String... columns) {
        return Arrays.stream(columns).map(this::columnToString).collect(joining(StringPool.COMMA));
    }

    /**
     * 获取表名
     *
     * @return
     */
    public String getTableName() {
        return this.table != null ? this.table.getTableName() : "";
    }

    /**
     * 获取更新字段集合
     *
     * @param updateMap
     * @return
     */
    public String getUpdateSetByMap(Map<String, Object> updateMap) {
        if (updateMap == null || updateMap.size() == 0) {
            return StringPool.EMPTY;
        }

        String result = StringPool.EMPTY;
        int index = 0;
        String pkField = table.getKeyProperty();
        if (updateMap.containsKey(pkField)) {
            updateMap.remove(pkField);
        }
        for (Map.Entry<String, Object> entry : updateMap.entrySet()) {
            // 获取字段名
            String field = entry.getKey();
            // 跳过不允许修改的字段
            if (table.getFinalFieldList().contains(field)) {
                continue;
            }
            if (index > 0) {
                result += StringPool.COMMA;
            }

            String column = TableHelperUtil.getEntityFieldColumn(this.entityClass, field);
            if (entry.getValue() == null) {
                result += column + StringPool.EQUALS + "null";
            } else {
                result += String.format("%s=%s", column, formatSql(entry.getValue()));
            }
            index++;
        }
        return result;
    }

    public Boolean isLogicDelete() {
        return table.isLogicDelete();
    }

    public void setLogicCondition() {
        if (isLogicDelete()) {
            TableColumnInfo field = table.getColumnList().stream().filter(TableColumnInfo::isLogicDelete).findFirst().get();
            String sql = StringPool.EMPTY;
            if (field.getPropertyType() == String.class) {
                sql = field.getColumn() + StringPool.SPACE + StringPool.EQUALS + StringPool.SPACE + StringPool.SINGLE_QUOTE + field.getLogicNotDeleteValue() + StringPool.SINGLE_QUOTE;
            } else {
                sql = field.getColumn() + StringPool.SPACE + StringPool.EQUALS + StringPool.SPACE + field.getLogicNotDeleteValue();
            }
            this.connect(sql);
        }
    }

    public Class<T> getEntityClass() {
        return this.entityClass;
    }

    @Override
    public void clear() {
        this.lambdaWrapper = null;
        super.clear();
    }

}